// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: leon

#pragma once

#include <cmath>
#include <map>
#include <unordered_set>
#include <string>

namespace coin2::exchange::uniswap::api_util {

std::map<std::string, double> TOKEN_ADDRESS_TO_DECIMAL_MULTIPLIER = {
    {"0x0000000000000000000000000000000000000000", 1e-18},
    {"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 1e-18},
    {"0x6B175474E89094C44Da98b954EedeAC495271d0F", 1e-18},
    {"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 1e-6},
    {"0x0D8775F648430679A709E98d2b0Cb6250d2887EF", 1e-18},
    {"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 1e-8},
    {"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", 1e-18},
    {"0xA0335820dC549dBfae5b8D691331CadfCA7026E0", 1e-18},
    {"0xdAC17F958D2ee523a2206206994597C13D831ec7", 1e-6},
    {"0x1D6405138A335cE5FD7364086334EfB3E4F28B59", 1e-18},
    // arbitrum case
    {"0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", 1e-18},
    {"0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", 1e-6},
    {"0x912CE59144191C1204E64559FE8253a0e49E6548", 1e-18},
    {"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", 1e-6},
    {"0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", 1e-8},
    {"0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0", 1e-18},
};

std::unordered_set<std::string> TOKEN_ADDRESS_QUOTE_SET = {
  "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
  "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"
};

struct NftTokenInfo {
    std::string token0_address;
    std::string token1_address;
    int32_t fee;
    int32_t tick_lower;
    int32_t tick_upper;
    std::string liquidity;
};

inline bool IsInversePair(const NftTokenInfo& nft_token_info) {
  if (TOKEN_ADDRESS_QUOTE_SET.count(nft_token_info.token0_address) > 0 && TOKEN_ADDRESS_QUOTE_SET.count(nft_token_info.token1_address) == 0) {
    return true;
  }
  return false;
}

inline std::pair<double, double> CalculateNftLiquidityPrice(const NftTokenInfo& nft_token_info) {
  bool inverse = IsInversePair(nft_token_info);
  double token0_decimal_multiplier = TOKEN_ADDRESS_TO_DECIMAL_MULTIPLIER[nft_token_info.token0_address];
  double token1_decimal_multiplier = TOKEN_ADDRESS_TO_DECIMAL_MULTIPLIER[nft_token_info.token1_address];
  double token0_token1_decimal_multiplier = token1_decimal_multiplier / token0_decimal_multiplier;
  double min_price = std::pow(1.0001, nft_token_info.tick_lower) * token0_token1_decimal_multiplier;
  double max_price = std::pow(1.0001, nft_token_info.tick_upper) * token0_token1_decimal_multiplier;
  if (inverse) {
    min_price = 1.0 / min_price;
    max_price = 1.0 / max_price;
  }
  return {min_price, max_price};
}
}  // namespace coin2::exchange::uniswap::api_util
